import subprocess
import threading
import tkinter as tk
from tkinter import ttk
from queue import Queue, Empty

# 全局变量
scan_queue = Queue()
ip_frames = {"used": {}, "free": {}}
network_prefix = ''
root = None
status_label = None
threads = []
update_ui_thread = None

def ping_ip(ip):
    try:
        # 使用ping命令检查IP地址是否响应
        response = subprocess.run(f'ping -n 1 {ip}', shell=True, stdout=subprocess.PIPE)
        return response.returncode == 0
    except Exception as e:
        print(f"Ping {ip} 出现异常: {e}")
        return False

def scan_ip(ip):
    try:
        is_used = ping_ip(ip)
        scan_queue.put((ip, is_used))
    except Exception as e:
        print(f"Error scanning IP {ip}: {e}")

def update_ui():
    while True:
        try:
            ip, is_used = scan_queue.get(timeout=1)
            if ip is None:
                break
            if is_used:
                ip_frames["used"].setdefault(network_prefix, []).append(ip)
            else:
                ip_frames["free"].setdefault(network_prefix, []).append(ip)
            refresh_ui()
        except Empty:
            pass
        if not scan_queue.empty():
            continue
        if update_ui_thread is None or not update_ui_thread.is_alive():
            break

def refresh_ui():
    # 刷新显示占用的IP
    for prefix, used_ips in ip_frames["used"].items():
        used_tabs[prefix].delete("1.0", tk.END)
        for ip in used_ips:
            used_tabs[prefix].insert(tk.END, ip + "\n")

    # 刷新显示空闲的IP
    for prefix, free_ips in ip_frames["free"].items():
        free_tabs[prefix].delete("1.0", tk.END)
        for ip in free_ips:
            free_tabs[prefix].insert(tk.END, ip + "\n")

    # 更新状态标签
    used_count = sum(len(v) for v in ip_frames['used'].values())
    free_count = sum(len(v) for v in ip_frames['free'].values())
    status_label.config(text=f"Used IPs: {used_count}, Free IPs: {free_count}")

def start_scan():
    global network_prefix, ip_frames, update_ui_thread
    network_prefix = ip_prefix_entry.get()
    if not network_prefix:
        network_prefix = '0'
    elif not network_prefix.endswith('.'):
        network_prefix += '.'
    scan_queue.queue.clear()
    ip_frames["used"] = {}
    ip_frames["free"] = {}
    refresh_ui()

    threads.clear()
    for i in range(256):
        for j in range(256):
            for k in range(256):
                ip = f"{network_prefix}{i}.{j}.{k}"
                thread = threading.Thread(target=scan_ip, args=(ip,))
                threads.append(thread)
                thread.start()

    # 启动UI更新线程
    update_ui_thread = threading.Thread(target=update_ui)
    update_ui_thread.start()

def on_closing():
    # 结束所有线程
    for thread in threads:
        thread.join()
    if update_ui_thread is not None:
        update_ui_thread.join()
    root.destroy()

# UI部分
root = tk.Tk()
root.title("IP Scanner")

# 状态标签
status_label = ttk.Label(root, text="Ready to Scan")
status_label.grid(row=0, column=0, columnspan=4, sticky=tk.W+tk.E, padx=10, pady=10)

# IP前缀输入
ttk.Label(root, text="IP Prefix:").grid(row=1, column=0, padx=10, pady=10)
ip_prefix_entry = ttk.Entry(root, width=15)
ip_prefix_entry.grid(row=1, column=1, padx=10, pady=10)
ip_prefix_entry.insert(0, '172.')

# 开始扫描按钮
scan_button = ttk.Button(root, text="Start Scan", command=start_scan)
scan_button.grid(row=1, column=2, padx=10, pady=10)

# Notebook
notebook = ttk.Notebook(root)
notebook.grid(row=2, column=0, columnspan=4, sticky="nsew", padx=10, pady=10)

# 用于显示占用IP的标签页
used_tab_frame = ttk.Frame(notebook)
notebook.add(used_tab_frame, text="Used IPs")
used_tabs = {network_prefix: tk.Text(used_tab_frame, height=10)}
used_tabs[network_prefix].pack(padx=10, pady=10)

# 用于显示空闲IP的标签页
free_tab_frame = ttk.Frame(notebook)
notebook.add(free_tab_frame, text="Free IPs")
free_tabs = {network_prefix: tk.Text(free_tab_frame, height=10)}
free_tabs[network_prefix].pack(padx=10, pady=10)

root.protocol("WM_DELETE_WINDOW", on_closing)
root.mainloop()